package com.javabasic.annotation;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;

/**
 * @Author xiongmin
 * @Description //TODO
 * @Date 2020/4/14 15:28
 * @Version 1.0
 *
 * 注解其实就是两个作用：
 *
 * 1. 让编译器检查代码
 * 2. 将数据注入到方法、成员变量、类上
 *
 * link: https://mp.weixin.qq.com/s/n-P8W8OzcKIg3UiFC-JycA
 **/
@Slf4j
public class AnnotationTest {

    public static void main(String[] args) {

        HashMap stringHashMap = new HashMap<>(3);
        stringHashMap.put("hans","hans");

        // 获取类的反射对象
        Class<Person> personClass = Person.class;
        try {
            // 反射出该类的方法
            Method add = personClass.getMethod("add", String.class, int.class);

            // 获取对应方法上的相应注解以及注解的属性值
            MyAnnotation myAnnotation = add.getAnnotation(MyAnnotation.class);
            String userName = myAnnotation.userName();
            int age = myAnnotation.age();

            // 将注解上的信息注入到方法上
            Person person = personClass.newInstance();
            add.invoke(person,userName,age);
        } catch (NoSuchMethodException e) {
            log.error(e.getMessage());
        } catch (IllegalAccessException e) {
            log.error(e.getMessage());
        } catch (InstantiationException e) {
            log.error(e.getMessage());
        } catch (InvocationTargetException e) {
            log.error(e.getMessage());
        }

        injectPerson();
    }

    // 注入person -- 通过注解注入对象
    public static void injectPerson() {
        try {
            PropertyDescriptor personDaoOfPerson_Property = new PropertyDescriptor("person", PersonDao.class);
            Person person = (Person) personDaoOfPerson_Property.getPropertyType().newInstance();
            Method writeMethod = personDaoOfPerson_Property.getWriteMethod();

            Annotation annotation = writeMethod.getAnnotation(MyAnnotation.class);

            Method[] methods = annotation.getClass().getMethods();

            for (Method method : methods) {
                String name = method.getName();
                System.out.println(name);
                try {
                    PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, Person.class);
                    Method writeMethod1 = propertyDescriptor.getWriteMethod();
                    Object invoke = method.invoke(annotation, null);

                    writeMethod1.invoke(person,invoke);
                } catch (Exception e) {
                    log.error(e.getMessage());
                } finally {
                    continue;
                }

            }

            PersonDao personDao = new PersonDao();
            writeMethod.invoke(personDao,person);
        } catch (IntrospectionException e) {
            log.error(e.getMessage());
        } catch (IllegalAccessException e) {
            log.error(e.getMessage());
        } catch (InstantiationException e) {
            log.error(e.getMessage());
        } catch (InvocationTargetException e) {
            log.error(e.getMessage());
        }

    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Person {
    private String userName;
    private int age;

    @MyAnnotation(userName = "xiaoz", age = 25)
    public void add(String userName, int age) {
        Person person = new Person(userName, age);
        System.out.println(person);
    }

}
@Data
@AllArgsConstructor
@NoArgsConstructor
class PersonDao {
    private Person person;

    @MyAnnotation(userName = "xiaoz", age = 25)
    public void setPerson(Person person) {
        System.out.println(person);
    }
}
